# -*- coding:utf-8 -*-

'''
实现注册/登陆/退出这些功能
'''
import re

import logging
from flask import request, jsonify
from flask import session

from ihome import redis_store, db
from ihome.api_1_0 import api
from ihome.models import User
from ihome.utils.common import login_required
from ihome.utils.response_code import RET


# 注册功能
# URL: /api/v1_0/users?mobile=17612345670&sms_code=1234&password=123456
# 请求参数: mobile(手机号) / sms_code(短信验证码)  / password(密码)
@api.route('/users', methods=['POST'])
def register():
    # 一 获取参数
    # request.ada
    # get_data 获取的是字符串数据,不便于后续的参数解析
    # 如果要用,需要配合json_loads()转换为字典格式的数据
    # req_data = request.get_data()
    # print 'req_data:', req_data  # ,'req_data.get("mobile")', req_data.get('data')

    # get_json: 方便的获取JSON数据,同时自动转换为字典
    req_json = request.get_json()
    # print 'req_json:', req_json
    mobile = req_json.get('mobile')  # 手机号
    sms_code = req_json.get('sms_code')  # 手机验证码
    passoword = req_json.get('password')  # 密码

    # 二 校验数据
    # 1.完整性
    if not all([mobile, sms_code, passoword]):
        resp = {
            'errno': RET.PARAMERR,
            'errmsg': '数据不完整,请重新提交',
            'userInfo': '请确保注册页面上所有的信息都已经填入'
        }
        return jsonify(resp)
    # 2.验证手机号
    if not re.match(r"1[3456789]\d{9}$", mobile):
        return jsonify(errno=RET.DATAERR, errmsg='手机号不正确', userInfo='手机号不正确,请重新提交')

    # 三 逻辑处理
    # 1.从redis中获取数据对比
    # 2.判断用户是否注册过,没注册就创建并保存用户
    # 3.(注册后直接登陆)保存session

    # 1.1 从redis读取数据
    try:
        real_sms_code = redis_store.get('sms_code_%s' % mobile)
    except Exception as e:
        logging.error(e)
        return jsonify(errno=RET.DBERR, errmsg='redis读取失败', userInfo='网络错误,请检查网络,并重新提交')

    # 1.2 判断数据是否为None 短信验证码过期
    if real_sms_code is None:
        return jsonify(errno=RET.DATAERR, errmsg='短信验证码为空,可能是验证码到期', userInfo='短信验证码过期,刷新页面,重新填写/提交数据')

    # 1.3 对比短信验证码
    if real_sms_code != sms_code:
        return jsonify(errno=RET.DATAERR, errmsg='短信验证码填写错误', userInfo='短信验证码填写错误,请修改后,重新提交')

    # 1.4 删除短信验证码
    try:
        redis_store.delete('sms_code_%s' % mobile)
    except Exception as e:
        logging.error(e)
        return jsonify(errno=RET.DBERR, errmsg='redis删除错误', userInfo='网络连接错误,请检查网络,再重新提交')

    # 2. 判断用户是否注册过,没注册的话创建并保存用户(密码保存,会在模型中做加密处理)
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        logging.error(e)
        return jsonify(errno=RET.DBERR, errmsg='MySQL数据库查询错误', userInfo='网络连接错误,请检查网络,再重新提交')
    else:
        if user is not None:
            # user不为空,说明手机号已经被注册
            return jsonify(errno=RET.DATAEXIST, errmsg='手机号已经被注册', userInfo='手机号已经被被注册,请更换手机号')
        # 若手机号为空,则保存注册信息到数据库 默认情况下 用户名为手机号
        user = User(name=mobile, mobile=mobile)
        # 对密码进行加密 为了符合规范,有关模型的数据操作一般在Models中进行
        # pbkdf2:sha256:50000$ey5Pg8Ie$4fca7afb538b79c4d6c66a4c8c3cae23c192f02bfa97e8c51605d1fa6cd08773
        user.password = passoword

        # 保存数据到数据库
        try:
            db.session.add(user)
            db.session.commit()
        except Exception as e:
            # 回滚提交操作
            db.session.rollback()
            logging.error(e)
            return jsonify(errno=RET.DBERR, errmsg='Mysq数据库保存失败', userInfo='网络错误,刷新页面,请重试尝试')

    # 3.(注册后直接登陆) 保存 session
    try:
        session['user_id'] = user.id
        session['user_name'] = user.name
        session['mobile'] = mobile
    except Exception as e:
        logging.error(e)
        return jsonify(errno=RET.SESSIONERR, errmsg='session保存失败', userInfo='网络错误,刷新页面,请重试尝试')

    # 四 返回结果
    return jsonify(errno=RET.OK, errmsg='注册成功', userInfo='注册成功')


# 登陆功能
# URL:/api/v1_0/sessions
# 参数:mobile(手机号) / password(密码)
@api.route('/sessions', methods=['POST'])
def lgoin():
    # 一 获取参数
    print '参数:', request.get_data()
    req_json = request.get_json()
    mobile = req_json.get('mobile')
    password = req_json.get('password')

    # 二 校验参数
    # 2.1 校验参数是否完整
    if not all([mobile, password]):
        return jsonify(error=RET.PARAMERR, errmsg='参数不全', userInfo='参数不全,请确认后,重新提交')
    # 2.2 校验手机号格式是否正确
    if not re.match(r'1[345678]\d{9}$', mobile):
        return jsonify(error=RET.PARAMERR, errmsg='输入的手机号格式不正确', userInfo='手机号格式不正确,请检查后,重新提交')

    # 三 逻辑处理
    # 3.1 从redis中获取登陆的错误次数 --> 如果错误次数超过5次,直接返回
    # 获取请求用户的IP地址
    user_ip = request.remote_addr

    # 获取用户错误请求的次数
    try:
        user_error_count = redis_store.get('user_error_count_%s' % user_ip)
    except Exception as e:
        logging.error(e)
        return jsonify(errno=RET.DBERR, errmsg='redis查询错误', userInfo='网络连接失败,请重试')

    # 如果错误请求的次数大于5次,则直接返回
    if user_error_count is not None and user_error_count > 5:
        return jsonify(errno=RET.IPERR, errmsg='连续登陆次数超过5次', userInfo='连续登陆次数超过5次,请10分钟之后再试')

    # 3.2 没有超过最大次数(0-4),查询用户是否存在,密码是否正确,如果有问题直接返回,并添加错误次数
    # 获取用户
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        logging.error(e)
        return jsonify(errno=RET.DBERR, errmsg='Mysql查询失败', userInfo='网络连接失败,请重试')

    # 用户为空 或者 密码不正确 添加错误次数后,直接返回
    if user is None or not user.check_password_hash(password):
        try:
            redis_store.incr('user_error_count_%s' % user_ip)
            redis_store.expire('user_error_count_%s' % user_ip)
        except Exception as e:
            logging.error(e)
            return jsonify(errno=RET.DBERR, errmsg='redis添加数据错误', userInfo='网络连接失败,请重试')
        return jsonify(error=RET.LOGINERR, errmsg='用户名或者密码错误', userInfo='用户名或者密码错误,请检查后重试')

    # 3.3 设置session数据
    try:
        session['user_id'] = user.id
        session['user_name'] = user.name
        session['mobile'] = user.mobile
    except Exception as e:
        logging.error(e)
        return jsonify(errno=RET.SESSIONERR, errmsg='session添加失败', userInfo='网络连接失败,请重试')

    # 3.4 删除redis的错误次数(重置)
    try:
        redis_store.delete('user_error_count_%s' % user_ip)
    except Exception as e:
        logging.error(e)
        return jsonify(errno=RET.DBERR, errmsg='redis删除失败')

    # 四 返回结果
    return jsonify(errno=RET.OK, errmsg='登陆成功')


# 检查登录状态
@api.route('/sessions', methods=['GET'])
def check_login():
    '''检查登录状态'''
    # 尝试从sessions中获取用户的名字
    name = session.get('user_name')
    # 如果session中的数据name名字存在,则表示用于已经登录,否则未登录
    if name is not None:
        return jsonify(errno=RET.OK, errmsg=True, userInfo='用户已登陆', data={'name': name})
    else:
        return jsonify(errno=RET.SESSIONERR, errmsg=False, userInfo='用户未登录')


# 退出登陆
@api.route('/sessions', methods=['DELETE'])
@login_required
def logout():
    '''退出'''
    # 清除session数据,csrf需要保留
    csrf_token = session['csrf_token']
    session.clear()
    session['csrf_token'] = csrf_token

    # 删除session的方式有3种,感觉就是字典的常用操作方式
    # 1.session.pop() # 2. 和Django相同 # 3. session.clear() 清空session
    return jsonify(errno=RET.OK, errmsg='OK')
